
geocoder = {};
map = {};
markersArray = [];
directionsGraph = {};
directionsRendererArray = [];
machinesData = [];
machinesIterator = {};

loadMachinesData();

$('.showPath').click( initPaths );

function loadMachinesData(){
	$.ajax({
		'type': 'GET',
		'url': 'LoadMachinesDataServlet',
		'dataType': 'json',
		'success': function( result ){
			initialize( result['machines'], result['trademarks'] );
		}
	});
	
}

function initialize( data, trademarks ) {
	machinesData = data;
	geocoder = new google.maps.Geocoder();
	var latlng = new google.maps.LatLng(50.060, 19.959);
	var mapOptions = {
		zoom : 13,
		center : latlng
	};
	map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
		
	buildStartChoiceSelect( machinesData );
	
	initTrademarksChoices( trademarks );
	initMachinesChoices( machinesData );
	
	initMarkers();
};

function buildStartChoiceSelect( machines ){
	var options = [];
	var hg = new HtmlGenerator();
	for( var i in machines ){
		options.push( {name: machines[i].machineName, value: i });
	}
	
	$('.id-starting-point-select').remove();
	$('.id-start-point').append( hg.select(options, 'id-starting-point-select') );
}

function initMachinesChoices( machines ){
	var hg = new HtmlGenerator();
	var fieldset = hg.fieldset( 'Automaty:');
	for( var i in machines ){
		var label = hg.label( machines[i].machineName );
		var input = hg.input( 'checkbox', '', '', machines[i].id );
		input.prop('checked', true );
		label.append( input );
		fieldset.append( label );
	}	
	$('.id-machines-choices').append( fieldset );
}

function initTrademarksChoices( trademarks ){
	var hg = new HtmlGenerator();
	var fieldset = hg.fieldset( 'Wyswietl automaty, w ktorych brakuje:' );
	for( var i in trademarks ){
		var label = hg.label( trademarks[i] );
		var input = hg.input( 'checkbox', '', trademarks[i] );
		input.prop( 'checked', true );
		label.append( input );
		fieldset.append( label );		
	}
	$('.trademarkChoices').append( fieldset );
}

function setState( state ){
	console.log( state );
	if( state == 'MARKERS_INITIALIZED' ){
		buildMarkersArrayFilters();		
		$('.trademarkChoices input:checkbox').click( buildMarkersArrayFilters );		
		$('.id-machines-choices input:checkbox').click( buildMarkersArrayFilters );
	}
}

function buildMarkersArrayFilters(){
	var trademarksChoices = [];
	$('.trademarkChoices input:checked').each( function(){		
		trademarksChoices.push( $(this).prop('name') );		
	});
	
	var machinesChoices = [];	
	$('.id-machines-choices input:checked').each( function(){
		machinesChoices.push( $(this).val() );		
	});
	
	var chosenMachinesFromTrademarksFilter = machinesData.filter( function( element ){
		for( var i in element.trademarks ){
			if( trademarksChoices.indexOf( element.trademarks[i].name ) > -1 && element.trademarks[i].currentAmount != element.trademarks[i].maxAmount ){
				return true;
			}
		}
		return false;
	});
	
	var chosenMachinesFromMachinesFilter = machinesData.filter( function( element ){
		return machinesChoices.indexOf( '' + element.id ) > -1 ? true : false;
	});
	
	chosenMachines = chosenMachinesFromMachinesFilter.filter(function(i) {return chosenMachinesFromTrademarksFilter.indexOf(i) > -1;});	
	
	clearPath();
	removeAllMarkers();
	if( chosenMachines.length > 0 ){
		for( var i in chosenMachines ){
			markersArray.push( chosenMachines[i].marker );
		}
		displayMarkers();
	}
}
	
function initMarkers(){
	machinesIterator = initArray(false, machinesData.length);
	
	for( var i in machinesData ){			
		var address = machinesData[i].address;
		var name = machinesData[i].machineName;
		with({index: i, name: name, address: address, states: machinesData[i].trademarks }){
			geocoder.geocode({
				'address' : address
			}, function(results, status) {				
				console.log( results, status );
				if (status == google.maps.GeocoderStatus.OK) {								
					var contentString = '<h3>'+name+'</h3><p>' + address + '<p>';
					for( var j in states ){						
						contentString += '<p>'+ states[j].name +': ' + states[j].currentAmount + '/' + states[j].maxAmount + '</p>';
					}
					var infowindow = new google.maps.InfoWindow({
						content : contentString,
						maxWidth : 200
					});
	
					var marker = new google.maps.Marker({
						position: results[0].geometry.location,
						title: name
					});
					
					google.maps.event.addListener(marker, 'click', function() {
						infowindow.open(map, marker);
					});		
					
					machinesData[index].marker = marker;
					
					machinesIterator.pop();
					if( machinesIterator.length == 0 ){
						setState( 'MARKERS_INITIALIZED' );
					}
				} else {
					alert("Nie udało się wygenerować mapy: " + status);
				}
			});	
		}
	}
}

function removeAllMarkers(){
	for( var i in markersArray ){
		markersArray[i].setMap(null);
	}
	markersArray = [];
}

function displayMarkers(){	
	for( var i in markersArray ){
		markersArray[i].setMap(map);
	}
}
 
function initGraph( paths ){
	for( var i in paths ){
		directionsGraph[i] = {};
	}
}

sourcePointer = destinationPointer = 0;

function incrementPointers(){
	destinationPointer++;
	if( destinationPointer >= paths.length ){
		destinationPointer = 0;
		sourcePointer++;	
	}
	
	if( destinationPointer == sourcePointer ){
		incrementPointers();
	}
	
	if( sourcePointer >= paths.length ){
		return false;
	} else {
		return true;
	}
}

progressBarCounter = 0;

function makeRequest(){
	var source = paths[sourcePointer];
	var destination = paths[destinationPointer];
	var directionsService = new google.maps.DirectionsService(); 			

	var request = {
		origin: source,
		destination: destination,
		travelMode: google.maps.DirectionsTravelMode.DRIVING
	};
			
	directionsService.route( request, function( response, status ){
		if( status == google.maps.DirectionsStatus.OK ){
			var totalDistance = 0;
			for( var index in response.routes[0].legs ){	
				var distance = response.routes[0].legs[index].distance.text;
				distance = parseFloat( distance.substr( 0, distance.length - 3 ).replace(/,/g, '.') );
				totalDistance += distance;				
			}

			directionsGraph[sourcePointer][destinationPointer] = {
				src: sourcePointer,
				destination: destinationPointer,
				distance: totalDistance,
				distance_units: 'km',
				gm_response: response
			};
			
			$('.id-progress-bar').css('width', ( (progressBarCounter++) / (paths.length * (paths.length - 1))) * 100 + '%' );
			
			$(directionsGraph).trigger('change');
		} else {
			setTimeout(makeRequest, 300);
		}			
	});	
}

$(directionsGraph).change( function(){
	if( incrementPointers() ){
		makeRequest();
	} else {
		var path = findShortestPath();
		displayPath( path );
	}
});

function displayPath( path ){
	for( var i = 0; i < path.length - 1; i++ ){			
		var directionsRenderer = new google.maps.DirectionsRenderer();    
		directionsRenderer.setMap( map );
		directionsRenderer.setOptions( {suppressMarkers: true });
		directionsRenderer.setDirections( directionsGraph[path[i]][path[i+1]].gm_response );
		directionsRendererArray.push( directionsRenderer );
	}
}

function clearPath(){
	if( directionsRendererArray.length > 0 ){
		for( var i in directionsRendererArray ){
			directionsRendererArray[i].setMap(null);
		}
	}
}

function initPaths(){	
	sourcePointer = destinationPointer = 0;
	$('.id-progress-bar').css('width', '0%');
	clearPath();
	progressBarCounter = 0;
	paths = $.map( markersArray, function(e){ return e.position; } ); 
	initGraph( paths );
	makeRequest();
}


function findShortestPath(){		
	graph = $.extend(true, {}, directionsGraph);
	numberOfElements = parseInt( Object.keys(graph).length - 1 );
	
	shortestPathSequence = initArray( 0, numberOfElements );
	currentPathSequence= initArray( 0, numberOfElements );
	pathSequencePointer = 0;

	visited = initArray( false, numberOfElements );
		
	distancesBetweenMachinesArray = initArray( 0, numberOfElements, numberOfElements );
	
	for( var i = 0; i < numberOfElements; i++ ){
		for( var j = 0; j < numberOfElements; j++ ){
			if( i != j ){ 
				distancesBetweenMachinesArray[i][j] = graph[i][j].distance;
			}
		}
	}
	
	shortestPathLength = 999999999;
	currentPathLength = 0;	

	startNode = $('.id-starting-point-select').val();
	
	TSP( startNode );
		
	return shortestPathSequence;
}

function TSP( node ){
	currentPathSequence[pathSequencePointer++] = node;
	
	if( pathSequencePointer < numberOfElements ){
		visited[node] = true;
		for( var u = 0; u < numberOfElements; u++ ){
			if( !visited[u] ){
				currentPathLength += distancesBetweenMachinesArray[node][u];
				TSP(u);
				currentPathLength -= distancesBetweenMachinesArray[node][u];
			}		
		}
		visited[node] = false;
	} else {
		if( currentPathLength < shortestPathLength ){
			shortestPathLength = currentPathLength;
			for( var u = 0; u < pathSequencePointer; u++ ){
				shortestPathSequence[u] = currentPathSequence[u];
			}
		}
	}
	pathSequencePointer--;
}

function initArray( defaultValue, xLength, yLength ){
	var array = [];
	for( var i = 0; i < xLength; i++ ){
		if( typeof(yLength) != 'undefined' ){
			array.push( initArray( defaultValue, yLength) );
		} else {
			array.push( defaultValue );
		}
	}
	return array;
}